import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author GAX
 * @date 2025-09-03
 */

// 创建共享资源类
public class SyncVsLock {
    public synchronized void m1() {
        System.out.println(Thread.currentThread().getName() + "\t" + "拿到锁进来了!");
        // 暂停几秒钟线程
        try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) { e.printStackTrace();};
    }

    private final Lock lock = new ReentrantLock();

    /**
     * 使用 ReentrantLock 的 tryLock 方法进行尝试性锁获取的示例方法。
     * 该方法演示了如何带超时时间地获取锁，避免了无限期阻塞。
     */
    public void m2() {
        try {
            // 核心：尝试获取锁，并设置最大等待时间
            // 1. 尝试获取锁，如果锁立即可用，则直接获取成功，返回true。
            // 2. 如果锁被其他线程持有，当前线程最多 5 秒钟的等待。
            // 3. 在 5 秒等待期内，如果锁被释放，则当前线程会获取到锁并返回true。
            // 4. 如果超过了 5 秒等待期锁仍未可用，则放弃等待，方法返回 false。
            if (lock.tryLock(5L, TimeUnit.SECONDS)) {
                // tryLock 返回 true，表示成功获取到锁
                // 注意：由于 tryLock 可能等待，一旦成功获取锁，必须要在 finally 块中释放，否则会导致死锁
                try {
                    // 成功进入临界区（由锁保护的代码块）
                    System.out.println(Thread.currentThread().getName() + "\t" + "拿到锁进来了!");

                    // 模拟需要受锁保护的业务逻辑执行时间
                    // 这里使用睡眠3秒来代表一个耗时的操作（如数据库操作、复杂计算等）
                    // 在此期间，锁一直被当前线程持有，其他尝试获取此锁的线程将会等待或超时
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace(); // 处理睡眠被中断的异常，这里简单打印
                    };
                } finally {
                    // 最终块：确保锁一定会被释放，这是防止死锁的关键
                    // 无论try块中的代码是正常执行完毕还是抛出异常，finally块中的代码都会执行
                    lock.unlock(); // 释放锁，让其他等待的线程有机会获取
                }
            } else {
                // tryLock 返回 false，表示在指定的 5 秒超时时间内未能获取到锁
                System.out.println(Thread.currentThread().getName() + "\t" + "抢锁失败，请重试！");
            }
        } catch (InterruptedException e) {
            // 捕获 tryLock 方法在等待过程中被中断的异常（Thread.interrupt()）
            // 这通常意味着外界希望取消当前的等待操作
            // 这里选择将检查异常转换为非检查异常并抛出，由上层调用者处理中断逻辑
            throw new RuntimeException(e);
        }
    }


    public static void main(String[] args) {
        SyncVsLock syncVsLock = new SyncVsLock();
//        new Thread(() -> {
//            syncVsLock.m1();
//        },"线程 1").start();
//
//        new Thread(() -> {
//            syncVsLock.m1();
//        },"线程 2").start();

        new Thread(() -> {
            syncVsLock.m2();
        },"线程 3").start();

        new Thread(() -> {
            syncVsLock.m2();
        },"线程 4").start();
    }
}
